import re
import Config
from lib.log.Logger import LOGGER
import lib.entity.MatchResult
import lib.core
import os.path
from lib.entity import VERB_USER_LIST, VERB_APP_LIST
from pyltp import (
    Segmentor,
    Postagger,
    Parser,
)

from lib.tools import mrtools

log = LOGGER

# todo  获取VOB关系的白名单
TEMP_PASS_WORD = ['包括', '为']

# todo 否定词表
NEGATIVE_WORDS = ['不', '没有']


def main():
    f = open(lib.core.SOURCE_PATH + Config.INPUT_FILE_NAME, 'r', encoding='utf-8')
    inputdata = f.read()
    inputs = re.split('[。；]', inputdata)

    ac = NlpAnalyzeController()
    for i in range(len(inputs)):
        print("".join("第%d句:" % i))
        print()
        ac.parseInputs(inputs[i] + '。')
        # 打印全部分析结果
        ac.printAnalyzeResult()

        l = ac.getAnalyzeMatchResult()
        for r in l:
            if r.toFilterString() != '':
                print('分析: ' + r.toFilterString())
        ac.release()
        print()

    pass


class NlpAnalyzeController:
    __line = ''
    __processline = ''  # todo 处理过的句子 临时先放着
    __words = None
    __postTags = None
    __arcs = None
    __resultList = None  # []
    __length = 0

    __segMentor = None
    __postTagger = None
    __parser = None

    def __init__(self):
        self.__line = ''
        self.__words = []
        self.__postTags = []
        self.__arcs = []
        self.__resultList = []
        self.__length = 0

        if self.__segMentor is None:
            cwsmodelpath = os.path.join(lib.core.SOURCE_PATH + Config.CWS_MODEL_PATH)
            self.__segMentor = Segmentor()
            self.__segMentor.load_with_lexicon(cwsmodelpath, lib.core.SOURCE_PATH + Config.PERINFO_DICT_PATH)
        if self.__postTagger is None:
            posmodelpath = os.path.join(lib.core.SOURCE_PATH + Config.POS_MODEL_PATH)
            self.__postTagger = Postagger()
            self.__postTagger.load_with_lexicon(posmodelpath,
                                                lib.core.SOURCE_PATH + Config.POSTTAG_DICT_PATH)  # 词性这个好像不生效
        if self.__parser is None:
            parmodelpath = os.path.join(lib.core.SOURCE_PATH + Config.PAR_MODEL_PATH)
            self.__parser = Parser()
            self.__parser.load(parmodelpath)
        pass

    def __del__(self):
        self.__segMentor.release()
        self.__postTagger.release()
        self.__parser.release()
        pass

    def release(self):
        self.__line = ''
        self.__processline = ''
        self.__words = []
        self.__postTags = []
        self.__arcs = []
        self.__resultList = []
        self.__length = 0
        pass

    def parseInputs(self, inputs):
        self.__line = inputs
        self.__processline = mrtools.preProcessLine(inputs)
        self.__words = self.__segMentor.segment(self.__processline)
        self.__length = len(self.__words)
        self.__postTags = self.__postTagger.postag(self.__words)
        self.__useForceDict()  # 使用外部词性词典或者临时词典强制更改句子成分
        self.__arcs = self.__parser.parse(self.__words, self.__postTags)
        pass

    # TODO 强制改词性 写到文件里
    def __useForceDict(self):

        for n, p in mrtools.TEMP_DICT:
            i = 0
            while i < self.__length:
                if self.__words[i] == n:
                    self.__postTags[i] = p
                if self.__words[i] in n:
                    mergeword = self.__words[i]
                    mergelist = [i]
                    start = i + 1
                    while mergeword != n and start < self.__length:
                        mergeword += self.__words[start]
                        mergelist.append(start)
                        if len(mergeword) > len(n):
                            break
                        start += 1
                    if mergeword == n:
                        start = mergelist[0]
                        for j in mergelist[1:]:
                            self.__words[start] += self.__words[j]
                        self.__postTags[start] = p
                        mergelist.reverse()
                        for j in mergelist[:-1]:
                            del self.__words[j]
                            del self.__postTags[j]
                        self.__length = len(self.__words)
                i += 1
        mrtools.TEMP_DICT = []
        mrtools.TEMP_DICT.extend(mrtools.POSTTAG_DICT)  # 临时词典用完清空

        pass

    # 获取分析过程结果
    def getAnalyzeResult(self):
        resstr = '\n' + self.__line + '\n\t'
        resstr += "\t".join(
            "(%d)`%s`'%s'{%d:%s[%s->%s]}%s" % (i, self.__words[i], self.__postTags[i],
                                               self.__arcs[i].head - 1, self.__arcs[i].relation,
                                               self.__words[self.__arcs[i].head - 1],
                                               self.__words[i], '\n' if (i + 1) % 4 == 0 else '') for i in
            range(self.__length))
        resstr += '\n'

        return resstr

    # 获取分析结果
    def getAnalyzeMatchResult(self, purpose: str = 'default'):
        voblist = self.__getVOBList()
        allverblist = self.__getVerbList()
        finishlist = set()

        for pv in allverblist:

            if pv in finishlist:
                continue  # 已经添加过了 跳过

            finishlist.add(pv)
            '''
                取verb 从vob关系入手，用该动词的全部并列东西作分析
            '''

            if self.__isNegativeVerb(pv):  # 否定词直接干掉
                continue

            verblist = [pv]
            verblist.extend(self.__getVerbCOOListById(pv))

            # todo
            negalist = []
            for v in verblist:
                if self.__isNegativeVerb(v):
                    negalist.append(v)

            inverblist = []  # 传参用动词列表
            for i in verblist:
                if self.__words[i] in lib.entity.VERB_USER_LIST['verb'] or \
                        self.__words[i] in lib.entity.VERB_APP_LIST['verb']:
                    inverblist.append(self.__words[i])

            mr = lib.entity.MatchResult.MatchResult(verb=inverblist, purpose=purpose, line=self.__line)

            '''
                取actor 只从SBV关系中取
            '''
            mractorid = self.__getSBVStartByID(pv)
            if mractorid is not pv:
                mr.actor = self.__words[mractorid]

            '''
                取名词列表，从所有动词中获取vob的宾语以及该宾语并列的名词
            '''
            nlist = []
            for v in verblist:
                for npair, vpair in voblist:
                    if v == vpair:
                        nlist.append(npair)
                        nlist.extend(self.__getCOOListById(npair))

            # todo
            nnegalist = []
            for v in negalist:
                for npair, vpair in voblist:
                    if v == vpair:
                        nnegalist.append(npair)
                        nnegalist.extend(self.__getCOOListById(npair))

            '''
                取pi，针对每个名词获取前后所有的关系子节点
            '''
            pis = []
            npis = []
            for n in nlist:
                perres = ''
                # start = self.__getATTStartById(n)
                start = self.__getChildStartbyId(n)
                end = self.__getChildEndById(n)
                while start <= end:
                    perres += self.__words[start]
                    start += 1
                # todo del
                if n in nnegalist:
                    npis.append(perres)
                else:
                    pis.append(perres)  # todo del
            mr.pi = pis
            mr.negapi = npis  # todo del

            '''
                判断获取的四元组是否有效
            '''
            if mr.isVaild():
                self.__resultList.append(mr)
                # todo 如果成功添加mr 更新完成列表 以免某些词语跳过
                finishlist.update(verblist)

        return self.__resultList

    # todo 通过COO 关系找一下VOB
    def __getVOBList(self):
        voblist = []
        for i in range(self.__length):
            if self.__arcs[i].relation == 'VOB' or self.__arcs[i].relation == 'POB':
                head = self.__arcs[i].head - 1
                pair = [i, head]
                # 从动词表里过滤一下
                if self.__words[head] in VERB_USER_LIST['verb'] or self.__words[head] in VERB_APP_LIST['verb'] \
                        or self.__words[head] in TEMP_PASS_WORD:
                    voblist.append(pair)

        return voblist

    def __getVerbList(self):
        verblist = []
        voblist = self.__getVOBList()
        for i in range(self.__length):
            if self.__postTags[i] == 'v' and \
                    (self.__words[i] in lib.entity.VERB_USER_LIST['verb'] or self.__words[i] in
                     lib.entity.VERB_APP_LIST['verb']):
                vlist = [i]
                vlist.extend(self.__getVerbCOOListById(i))
                for v in vlist:
                    flag = False
                    for nn, vv in voblist:
                        if v == vv:
                            verblist.append(i)
                            flag = True
                            break
                    if flag:
                        break
        return verblist

    # TODO 获取主语
    def __getSBVStartByID(self, iid):
        start = self.__getSBVStartByIdUseRelation(iid)
        if start != iid:
            return start

        return iid

    def __getSBVStartByIdUseRelation(self, iid):
        start = iid

        for i in range(iid, -1, -1):
            if self.__arcs[i].relation == 'SBV' and self.__arcs[i].head - 1 == iid:
                start = i
                break

        if iid == start and self.__arcs[iid].relation == 'VOB':
            # 选择提供之类的
            return self.__getSBVStartByIdUseRelation(self.__arcs[iid].head - 1)

        return start

    def __getCOOListById(self, start):
        coolist = []
        for i in range(start, self.__length):
            if self.__arcs[i].relation == 'COO' and self.__arcs[i].head - 1 == start:
                coolist.append(i)
                coolist.extend(self.__getCOOListById(i))

        return coolist

    def __getVerbCOOListById(self, start):
        coolist = []
        for i in range(start, self.__length):
            if (self.__arcs[i].relation == 'COO' or self.__arcs[i].relation == 'CMP') and \
                    self.__arcs[i].head - 1 == start and self.__postTags[self.__arcs[i].head - 1] == 'v':
                coolist.append(i)
                coolist.extend(self.__getVerbCOOListById(i))

        return coolist

    def __getATTStartById(self, iid):
        start = iid
        for i in range(iid, -1, -1):
            if self.__arcs[i].relation == 'ATT' and \
                    (self.__arcs[i].head - 1 == start or self.__arcs[i].head - 1 == iid):
                start = i

        return start

    def __getChildStartbyId(self, iid):
        start = iid
        for i in range(iid - 1, -1, -1):
            if self.__arcs[i].relation == 'COO' or self.__arcs[i].relation == 'WP':
                break
            if self.__arcs[i].relation != 'LAD' and self.__arcs[i].head - 1 == iid:
                start = i

        return self.__getChildStartbyId(start) if start != -1 and start != iid else iid

    def __getChildEndById(self, iid):
        end = iid
        for i in range(iid + 1, self.__length):
            if self.__arcs[i].relation == 'COO' or self.__arcs[i].relation == 'WP':
                break
            if self.__arcs[i].head - 1 == iid:
                end = i
        return self.__getChildEndById(end) if end != self.__length and end != iid else iid

    def __isNegativeVerb(self, iid):
        for i in range(iid - 1, -1, -1):
            if self.__arcs[i].relation == 'ADV' and self.__arcs[i].head - 1 == iid and \
                    self.__words[i] in NEGATIVE_WORDS:
                return True

        return False


if __name__ == '__main__':
    main()
